package com.interview.b_并发.c_java_内存模型_JMM.a_重排序;

import java.util.concurrent.CountDownLatch;

/**
 * 演示重排序现象
 * <p>
 * 线程内的代码 执行顺序 发生改变
 * <p>
 * 但是重排序不是每次都会发生
 * 所以需要循环重复 知道达到某个条件才停止 测试小概率事件
 */
public class OutOfOrderExecution {
    public static Long qk1 = 0L;
    public static Long qk2 = 0L;
    public static Long qk3 = 0L;
    public static Long qk4 = 0L;


    public static Long a = 0L;
    public static Long b = 0L;

    public static Long x = 0L;
    public static Long y = 0L;

    public static CountDownLatch countDownLatch;

    static class Thread1 extends Thread {
        @Override
        public void run() {
            try {
//                System.out.println(Thread.currentThread().getName() + "阻塞 : " + countDownLatch.getCount());
                countDownLatch.await();
//                System.out.println(Thread.currentThread().getName() + "放行 : " + countDownLatch.getCount());
            } catch (Exception e) {
                e.printStackTrace();
            }
            a = 1L;
            x = b;
        }
    }

    static class Thread2 extends Thread {
        @Override
        public void run() {
            try {
//                System.out.println(Thread.currentThread().getName() + "阻塞 : " + countDownLatch.getCount());
                countDownLatch.await();
//                System.out.println(Thread.currentThread().getName() + "放行 : " + countDownLatch.getCount());
            } catch (Exception e) {
                e.printStackTrace();
            }
            b = 1L;
            y = a;
        }
    }


    /**
     * 循环 99 亿次（太难了，也不出来啊）
     * 如果没有发生重排序
     * 只存在 0,1   1,0   1,1  三种情况
     * <p>
     * 出现重排序，会出现 0,0
     * <p>
     * <p>
     * 原因
     * 线程1 修改了 a 的值
     * 但是没有写回到主存
     * 线程2 看到的  a值并没有变化
     * 所以最终结果一致为了优化减少指令 进行了重排序处理
     */
    public static void main(String[] args) throws InterruptedException {
        for (long i = 0L; i < 9999999999L; i++) {
            x = 0L;
            y = 0L;
            a = 0L;
            b = 0L;

            countDownLatch = new CountDownLatch(1);

            Thread1 thread1 = new Thread1();
            Thread2 thread2 = new Thread2();

            thread1.start();
            thread2.start();

            Thread.sleep(10);
            countDownLatch.countDown();

            thread1.join();
            thread2.join();

            if (x == 0L && y == 0L) {
                qk1++;
                System.out.println("第" + i + "次 出现重排序（乱序现象）   x=0  y=0");
                break;
            }

            if (x == 1L && y == 1L) {
                //                System.out.println("第" + i + "次 出现重排序（乱序现象）   x=1  y=1");
                qk2++;
                //                break;
            }
            //
            if (x == 0L && y == 1L) {
                //                System.out.println("第" + i + "次 出现重排序（乱序现象）   x=0  y=1");
                qk3++;
                //                break;
            }
            //
            if (x == 1L && y == 0L) {
                //                System.out.println("第" + i + "次 出现重排序（乱序现象）   x=1  y=0");
                qk4++;
                //                break;
            }
            //            System.out.println("第" + i + "次     x=" + x + " y=" + y);
        }

        //        (内存重排序)
        //        第116723次 出现重排序（乱序现象）   x=0  y=0
        //        情况1  1次    x=0  y=0
        //        情况2  1次    x=1  y=1
        //        情况3  100613次    x=0  y=1
        //        情况4  16109次    x=1  y=0

        System.out.println("情况1  " + qk1 + "次    x=0  y=0");
        System.out.println("情况2  " + qk2 + "次    x=1  y=1 ");
        System.out.println("情况3  " + qk3 + "次    x=0  y=1");
        System.out.println("情况4  " + qk4 + "次    x=1  y=0");

    }

}
